package com.zhangxin.aiInterview.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhangxin.aiInterview.common.ErrorCode;
import com.zhangxin.aiInterview.constant.PythonConstant;
import com.zhangxin.aiInterview.exception.BusinessException;
import com.zhangxin.aiInterview.manager.work_flow.tec_interview_analyze.TecInterviewAnalyze;
import com.zhangxin.aiInterview.manager.work_flow.tec_interview_analyze.model.TecInterviewAnalysisResult;
import com.zhangxin.aiInterview.manager.python_api.PythonApi;
import com.zhangxin.aiInterview.manager.redis.audio_emotion.DeleteAudioEmotion;
import com.zhangxin.aiInterview.manager.redis.audio_emotion.GetAudioEmotion;
import com.zhangxin.aiInterview.manager.redis.audio_speed.DeleteAudioSpeed;
import com.zhangxin.aiInterview.manager.redis.audio_speed.GetAudioSpeeds;
import com.zhangxin.aiInterview.manager.redis.audio_speed.model.AudioSpeedEntry;
import com.zhangxin.aiInterview.model.dto.interview.AnalyzeTecInterviewRequest;
import com.zhangxin.aiInterview.model.entity.*;
import com.zhangxin.aiInterview.model.enums.AnalyzeStatusEnum;
import com.zhangxin.aiInterview.model.enums.IsFullInterviewEnum;
import com.zhangxin.aiInterview.service.*;
import com.zhangxin.aiInterview.mapper.AiInterviewMapper;
import com.zhangxin.aiInterview.utils.BodyActionManager;
import com.zhangxin.aiInterview.utils.FaceActionManager;
import com.zhangxin.aiInterview.utils.FaceEmotionManager;
import com.zhangxin.aiInterview.utils.StressManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import static com.zhangxin.aiInterview.constant.PythonConstant.python_base_url_http;

/**
 * @author ZX
 * @description 针对表【ai_interview(AI模拟面试记录)】的数据库操作Service实现
 * @createDate 2025-04-25 14:58:29
 */
@Service
public class AiInterviewServiceImpl extends ServiceImpl<AiInterviewMapper, AiInterview>
        implements AiInterviewService {
    @Resource
    private UserService userService;
    @Resource
    private AiInterviewContentService aiInterviewContentService;
    @Resource
    private GetAudioSpeeds getAudioSpeeds;
    @Resource
    private GetAudioEmotion getAudioEmotion;
    @Resource
    private FaceActionManager faceActionManager;
    @Resource
    private BodyActionManager bodyActionManager;
    @Resource
    private FaceEmotionManager faceEmotionManager;
    @Resource
    private DeleteAudioEmotion deleteAudioEmotion;
    @Resource
    private DeleteAudioSpeed deleteAudioSpeed;
    @Resource
    private AiInterviewAnalyzeResultService aiInterviewAnalyzeResultService;
    @Resource
    private FullProcessInterviewService fullProcessInterviewService;
    @Resource
    private FullProcessAnalyzeResultService fullProcessAnalyzeResultService;
    @Resource
    private CompanyService companyService;
    @Resource
    private StressManager stressManager;
    @Resource
    private PythonApi pythonApi;
    @Resource
    private TransactionTemplate transactionTemplate;

    /**
     * 建立大语言模型和文字转语音模型的websocket连接
     *
     * @param request
     */
    @Override
    public void connect(HttpServletRequest request) {
        //获取用户id
        Long userId = userService.getLoginUser(request).getId();
        //初始化大语言模型和tts websocket连接
        try {
//            LLmWsManager.init(userId);
//            TtsWs.init(userId);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 技术面分析
     *
     * @param analyzeTecInterviewRequest
     * @param request
     * @param isFull
     * @param fullInterviewId
     */
    @Override
    @Transactional
    public void analyzeTecInterview(AnalyzeTecInterviewRequest analyzeTecInterviewRequest, HttpServletRequest request, Boolean isFull, Long fullInterviewId) {
        Long userId = userService.getLoginUser(request).getId();
        Long aiInterviewId = analyzeTecInterviewRequest.getAiInterviewId();

        //更新面试状态和时间
        boolean updateDuration = lambdaUpdate()
                .eq(AiInterview::getId, aiInterviewId)
                .set(AiInterview::getInterviewStatus, AnalyzeStatusEnum.ANALYZING.getValue())
                .set(AiInterview::getInterviewDuration, analyzeTecInterviewRequest.getInterviewDuration())
                .update();
        if (!updateDuration) throw new BusinessException(ErrorCode.OPERATION_ERROR, "更新面试时间失败");

        List<AnalyzeTecInterviewRequest.InterviewContent> interviewContentList = analyzeTecInterviewRequest.getInterviewContentList();

        //预处理数据
        interviewContentList.remove(0);
        interviewContentList.remove(interviewContentList.size() - 1);

        //保存面试内容
        boolean update = aiInterviewContentService.lambdaUpdate()
                .eq(AiInterviewContent::getAiInterviewId, analyzeTecInterviewRequest.getAiInterviewId())
                .set(AiInterviewContent::getInterviewContent, JSONUtil.toJsonStr(interviewContentList))
                .update();
        if (!update) {
            log.error("更新技术面试内容失败");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "更新技术面试内容失败");
        }

        // 保存当前面试数据
        //1 保存文本语速数据
        List<AudioSpeedEntry> audioSpeeds = getAudioSpeeds.getAudioSpeeds(userId);
        AiInterviewContent aiInterviewContent = new AiInterviewContent();
        aiInterviewContent.setSpeechRate(JSONUtil.toJsonStr(audioSpeeds));
        //2. 保存音频情感数据
        List<String> emotions = getAudioEmotion.getAllEmotions(userId);
        aiInterviewContent.setAudioEmotion(JSONUtil.toJsonStr(emotions));
        //3. 保存面部动作数据
        List<FaceActionManager.FaceAction> faceActions = faceActionManager.getFaceActions(userId);
        aiInterviewContent.setFacialActions(JSONUtil.toJsonStr(faceActions));
        //清空面部动作数据
        faceActionManager.clearUserData(userId.toString());
        //4. 保存躯体动作数据
        List<BodyActionManager.BodyAction> bodyActions = bodyActionManager.getBodyActions(userId);
        aiInterviewContent.setBodyMovements(JSONUtil.toJsonStr(bodyActions));
        //清空躯体动作数据
        bodyActionManager.clearUserData(userId.toString());
        //5. 保存面部情感数据
        List<String> faceEmotionStorageEmotions = faceEmotionManager.getEmotions(userId);
        aiInterviewContent.setMicroExpression(JSONUtil.toJsonStr(faceEmotionStorageEmotions));
        //清空面部情感数据
        faceEmotionManager.clearEmotions(userId);
        //6.保存面试压力数据
        List<String> stress = stressManager.getStress(userId);
        aiInterviewContent.setStress(JSONUtil.toJsonStr(stress));
        //清空用户压力数据
        stressManager.clearStress(userId);

        //存储技术面内容数据
        boolean update1 = aiInterviewContentService.lambdaUpdate()
                .eq(AiInterviewContent::getAiInterviewId, aiInterviewId)
                .set(AiInterviewContent::getSpeechRate, aiInterviewContent.getSpeechRate())
                .set(AiInterviewContent::getAudioEmotion, aiInterviewContent.getAudioEmotion())
                .set(AiInterviewContent::getFacialActions, aiInterviewContent.getFacialActions())
                .set(AiInterviewContent::getBodyMovements, aiInterviewContent.getBodyMovements())
                .set(AiInterviewContent::getMicroExpression, aiInterviewContent.getMicroExpression())
                .set(AiInterviewContent::getStress, aiInterviewContent.getStress())
                .update();
        if (!update1) throw new BusinessException(ErrorCode.OPERATION_ERROR, "保存面试数据失败");
        // 更新面试状态
        lambdaUpdate()
                .eq(AiInterview::getId, aiInterviewId)
                .set(AiInterview::getInterviewStatus, AnalyzeStatusEnum.ANALYZING.getValue())
                .update();

        // 异步分析技术面试结果并保存到数据库
        CompletableFuture.runAsync(() -> {
            // 1. 解析技术面试结果（替换为实际参数）
            TecInterviewAnalysisResult tecInterviewAnalysisResult = null;
            try {
                // 调用技术面工作流分析技术面试
                tecInterviewAnalysisResult = TecInterviewAnalyze.analyzeTecInterview(userId, aiInterviewId);
            } catch (Exception e) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "分析技术面试结果失败" + e.getMessage());
            }

            // 2. 创建目标对象并填充字段
            AiInterviewAnalyzeResult aiInterviewAnalyzeResult = new AiInterviewAnalyzeResult();
            aiInterviewAnalyzeResult.setAiInterviewId(aiInterviewId);

            aiInterviewAnalyzeResult.setCommunicationSummary(tecInterviewAnalysisResult.getCommunicationSummary());
            aiInterviewAnalyzeResult.setMultimodalSummary(tecInterviewAnalysisResult.getMultimodalSummary());
            aiInterviewAnalyzeResult.setTechnicalSummary(tecInterviewAnalysisResult.getTechnicalSummary());

            // 转为 JSON 字符串（List -> String）
            if (tecInterviewAnalysisResult.getMultimodalQuestions() != null) {
                aiInterviewAnalyzeResult.setMultimodalQuestions(
                        JSONUtil.toJsonStr(tecInterviewAnalysisResult.getMultimodalQuestions()));
            }

            if (tecInterviewAnalysisResult.getTechnicalQuestions() != null) {
                aiInterviewAnalyzeResult.setTechnicalQuestions(
                        JSONUtil.toJsonStr(tecInterviewAnalysisResult.getTechnicalQuestions()));
            }

            //设置分数
            if (tecInterviewAnalysisResult.getScores() != null) {
                aiInterviewAnalyzeResult.setScores(
                        JSONUtil.toJsonStr(tecInterviewAnalysisResult.getScores()));
            }
            //多模态评分
            Double totalScore = pythonApi.interviewMultimodalScoring(aiInterviewContent, userId, python_base_url_http + "/multimodal/scoring");
            aiInterviewAnalyzeResult.setTotalScore(totalScore.intValue());

            // 3. 保存技术面分析结果到数据库
            aiInterviewAnalyzeResultService.save(aiInterviewAnalyzeResult);

            //查看是否为全流程面试（回写技术分析结果id）
            if (isFull) {
                fullProcessAnalyzeResultService.lambdaUpdate()
                        .eq(FullProcessAnalyzeResult::getFullInterviewId, fullInterviewId)
                        .set(FullProcessAnalyzeResult::getTechInterviewAnalysisId, aiInterviewAnalyzeResult.getId())
                        .update();
            }

            //修改技术面试状态(已完成)
            lambdaUpdate()
                    .eq(AiInterview::getId, aiInterviewId)
                    .set(AiInterview::getInterviewStatus, AnalyzeStatusEnum.COMPLETED.getValue())
                    .set(AiInterview::getInterviewResultId, aiInterviewAnalyzeResult.getId())
                    .update();
        }).exceptionally(ex -> {
            log.error("分析技术面试结果失败", ex);
            return null;
        });

        // 清空redis中的分析数据
        deleteAudioEmotion.deleteAllEmotions(userId);
        deleteAudioSpeed.deleteAllSpeedRecords(userId);
    }

    /**
     * 生成技术面试
     *
     * @param userId
     * @param position
     * @param positionName
     * @param techFieldName
     * @param companyId
     * @param resumeId
     * @param interviewerGender
     * @param languageMode
     * @param isFull
     * @param fullInterviewId
     * @return
     */
    @Override
    public Long generateTecInterview(Long userId, Position position, String positionName, String techFieldName, Long companyId, Long resumeId, String interviewerGender, String languageMode, String interviewerType, Boolean isFull, Long fullInterviewId) {
        String company = companyService.getById(companyId).getName();

        //保存技术面试数据
        AiInterview aiInterview = new AiInterview();
        aiInterview.setResumeId(resumeId);
        aiInterview.setTechField(techFieldName);
        aiInterview.setPosition(positionName);
        aiInterview.setCompany(company);
        aiInterview.setLanguage(languageMode);
        aiInterview.setInterviewer(interviewerGender);
        aiInterview.setInterviewerType(interviewerType);
        aiInterview.setUserId(userId);
        aiInterview.setInterviewStatus(AnalyzeStatusEnum.UNFINISHED.getValue());
        //判断是否为全流程面试
        if (isFull) {
            aiInterview.setIsFull(IsFullInterviewEnum.FULL_INTERVIEW.getValue());
        } else {
            aiInterview.setIsFull(IsFullInterviewEnum.IS_NOT_FULL_INTERVIEW.getValue());
        }
        save(aiInterview);

        //保存面试内容数据
        AiInterviewContent aiInterviewContent = new AiInterviewContent();
        aiInterviewContent.setAiInterviewId(aiInterview.getId());
        aiInterviewContent.setUserId(userId);
        aiInterviewContent.setInterviewContent("");
        aiInterviewContentService.save(aiInterviewContent);

        //是否为全流程面试(回写技术面id)
        if (isFull) {
            fullProcessInterviewService.lambdaUpdate()
                    .eq(FullProcessInterview::getId, fullInterviewId)
                    .set(FullProcessInterview::getAiInterviewId, aiInterview.getId())
                    .update();
        }

        //返回面试id
        return aiInterview.getId();
    }

    /**
     * 删除技术面试记录和相关信息
     * @param tecInterviewId
     * @param request
     * @return
     */
    @Override
    public boolean deleteTecInterview(Long tecInterviewId, HttpServletRequest request) {
        //开启方法事务
        transactionTemplate.execute(status -> {
            try {
                // 删除技术面记录
                removeById(tecInterviewId);

                // 删除技术面内容
                QueryWrapper<AiInterviewContent> aiInterviewContentQueryWrapper = new QueryWrapper<>();
                aiInterviewContentQueryWrapper.eq("aiInterviewId", tecInterviewId);
                aiInterviewContentService.remove(aiInterviewContentQueryWrapper);

                // 删除技术面分析结果
                QueryWrapper<AiInterviewAnalyzeResult> aiInterviewAnalyzeResultQueryWrapper = new QueryWrapper<>();
                aiInterviewAnalyzeResultQueryWrapper.eq("aiInterviewId", tecInterviewId);
                aiInterviewAnalyzeResultService.remove(aiInterviewAnalyzeResultQueryWrapper);

            } catch (Exception e) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR, "删除技术面记录相关信息失败，id为::"+tecInterviewId+"，报错信息" + e.getMessage());
            }
            return null;
        });
        return true;
    }
}




